﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Xml;
using System.Net;
using Xeml.Document.Manager;
using Xeml.Document.Contracts;
using Xeml.Document.Ontologies.OBO;
using System.Text.RegularExpressions;

namespace Xeml.Document.Ontologies.Environment
{
    public class GeneralOntologyHandler: IOntologyHandler, IDynamicOntologyHandler, IHierarchicalView
    {
        private IOntologyHandler ontologyHandler;
        private LoadedEventHandler _onLoaded;
        public event LoadedEventHandler OnLoaded {
            add {
			    if (_onLoaded == null || !_onLoaded.GetInvocationList().Contains(value))
			    {
			        _onLoaded += value;
			    }
			}
            remove
		    {
			    _onLoaded -= value;
            }
        }

        #region constructors
        public GeneralOntologyHandler() : base()
        {
            ontologyHandler = new GeneralOboHandler();
        }

        public GeneralOntologyHandler(string uri): base()
        { 
            ontologyHandler = new GeneralOboHandler();
        }

        public GeneralOntologyHandler(string uri, string url)
            : base()
        {
            ontologyHandler = GetHandler(url);
            _uri = uri;
        }

        public GeneralOntologyHandler(GeneralOntologyHandler that)
            : base() 
        {
            if (ontologyHandler != null)
            {
                ontologyHandler = (IOntologyHandler)ontologyHandler.Copy();
            }
        }
        #endregion

        #region handler choosing
        public IOntologyHandler GetHandler(string url)
        {
            // determing file type
            TextReader txr = new StringReader(OnlineCacheManager.Instance.DownloadContent(url));
            FileType? fileType = getFileType(txr.ReadToEnd());

            switch (fileType)
            {
                case FileType.obo:
                    ontologyHandler = new GeneralOboHandler();
                    ontologyHandler.InstanceLocation = url;
                    break;
                case FileType.xml: break;
                default: // TODO enable user to set the file type
                    throw new Exception("File type of ontology could not be determined!");
            }

            return ontologyHandler;
        }

        /// <summary>
        /// Define which file types we can parse
        /// </summary>
        private enum FileType {
            obo,
            xml
        }

        /// <summary>
        /// Determine which FileType the contents.
        /// </summary>
        /// <param name="contents">The contents of a file to check</param>
        /// <returns></returns>
        private FileType? getFileType(String contents)
        {
            // determine if this is obo: http://www.geneontology.org/GO.format.obo-1_4.shtml
            Match match = Regex.Match(contents, @"format-version\s*:"); // mandatory tag
            if (match.Success)
            {
                Match matchTerm = Regex.Match(contents, @"[Term]"); // another mandatory tag
                if (matchTerm.Success)
                {
                    return FileType.obo;
                }
            }

            match = Regex.Match(contents, @"<?xml");
            if (match.Success)
            {
                return FileType.xml;
            }

            return null;
        }
        #endregion

        #region IXemlComponent Members
        public string Publisher
        {
            get { return "Kenny Billiau"; }
        }

        public Version Version
        {
            get { return new Version(1, 0, 0, 0); } 
        }

        public string ComponentName
        {
            get { return "General Ontology Handler"; }
        }

        public string Author
        {
            get { return "Kenny Billiau"; }
        }

        public string Description
        {
            get { return "You can chose your own URL!"; }
        }

        private String _uri = "http://gmd.mpimp-golm.mpg.de/2014/XEML/GeneralOntologyHandler"; 
        public string Uri
        {
            get { return _uri; }
        }

        public IXemlComponent Copy()
        {
            return new GeneralOntologyHandler(this);
        }
        #endregion

        public string NameSpace
        {
            get { return ontologyHandler.NameSpace; }
        }

        public bool AutoValidation
        {
            get
            {
                return ontologyHandler.AutoValidation;
            }
            set
            {
                ontologyHandler.AutoValidation = value;
            }
        }

        public string InstanceLocation
        {
            get
            {
                return ontologyHandler.InstanceLocation;
            }
            set
            {
                ontologyHandler.InstanceLocation = value;
            }
        }

        public string OntologyLoadMessage
        {
            get { return ontologyHandler.OntologyLoadMessage; }
        }

        public OntologyLoadState OntologyLoadState
        {
            get { return ontologyHandler.OntologyLoadState; }
        }

        public OntologyType OntologyType
        {
            get { return OntologyType.Environment; } // TODO make adjustable by user!
        }

        public void Load(string nameSpaceAlias)
        {
            ontologyHandler.Load(nameSpaceAlias);
            if (_onLoaded != null)
            {
                _onLoaded(this, new LoadStateChangedEventArgs(ontologyHandler.OntologyLoadState));
            }
        }

        public void Load(string nameSpaceAlias, bool force)
        {
            ontologyHandler.Load(nameSpaceAlias, force);
            if (_onLoaded != null)
            {
                _onLoaded(this, new LoadStateChangedEventArgs(ontologyHandler.OntologyLoadState));
            }
        }

        public event EventHandler<ValidationMessage> Validation;

        #region IDynamicOntologyHandler
        public IEnumerable<IDynamicOntologyTerm> Terms
        {
            get
            {
                IDynamicOntologyHandler dynamicOntologyHandler = ontologyHandler as IDynamicOntologyHandler;
                if (dynamicOntologyHandler != null)
                {
                    return dynamicOntologyHandler.Terms;
                }
                return null;
            }
        }

        public IDynamicOntologyTerm Find(Term param)
        {
            IDynamicOntologyHandler dynamicOntologyHandler = ontologyHandler as IDynamicOntologyHandler;
            if (dynamicOntologyHandler != null)
            {
                return dynamicOntologyHandler.Find(param);
            }
            return null;
        }

        public IDynamicOntologyTerm Find(string termId)
        {
            IDynamicOntologyHandler dynamicOntologyHandler = ontologyHandler as IDynamicOntologyHandler;
            if (dynamicOntologyHandler != null)
            {
                return dynamicOntologyHandler.Find(termId);
            }
            return null;
        }
        #endregion

        #region Hierarchical interface
        public IEnumerable<TermNode> Nodes
        {
            get
            {
                IHierarchicalView hierarchicalOntologyHandler = ontologyHandler as IHierarchicalView;
                if (hierarchicalOntologyHandler != null)
                {
                    return hierarchicalOntologyHandler.Nodes;
                }
                return null;
            }
        }

        public TermNode FindNode(IOntologyTerm t)
        {
            IHierarchicalView hierarchicalOntologyHandler = ontologyHandler as IHierarchicalView;
            if (hierarchicalOntologyHandler != null)
            {
                return hierarchicalOntologyHandler.FindNode(t);
            }
            return null;
        }

        public TermNode FindNode(string termid)
        {
            IHierarchicalView hierarchicalOntologyHandler = ontologyHandler as IHierarchicalView;
            if (hierarchicalOntologyHandler != null)
            {
                return hierarchicalOntologyHandler.FindNode(termid);
            }
            return null;
        }
        #endregion

    }
}
